An introduction to neural nets and convnets with Keras

In [ ]:
# setup imports
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import sklearn
import sklearn.datasets
import tqdm # for fancy progress bars
import keras
import ipywidgets as widgets

A simple neural net with keras

In [ ]:
model = keras.models.Sequential()
model.add(keras.layers.Dense(1,input_shape = (2,)))
model.compile(optimizer=keras.optimizers.sgd(),loss="binary_crossentropy")
model.summary()

Get the (randomly initialized) weights

In [ ]:
model.layers[0].get_weights()

Set the weights

In [ ]:
weights = np.array([[0.8],[-1.0]])
bias = np.array([4.0])
model.layers[0].set_weights([weights, bias])

And predict

In [ ]:
data = np.array([[1,2]])
model.predict(data)

We can also compute gradients (of anything w.r.t. anything!)

In [ ]:
grads = keras.backend.gradients(model.output, model.weights)
f = keras.backend.function([model.input], grads)
myInput = np.array([[1,3]])
gradients_of_parameters = f([myInput])
print("Gradients of the output w.r.t. the weights:\n",gradients_of_parameters[0])
print("Gradients of the output w.r.t. the bias:\n",gradients_of_parameters[1])

Let's make a dataset for classification

In [ ]:
X,y = sklearn.datasets.make_moons(n_samples=250, shuffle=True, noise=0.25, random_state=None)
fig,ax = plt.subplots(figsize=(18,8))         
ax.scatter(X[:,0],X[:,1],c = y.astype(float), cmap="coolwarm")

xgrid,ygrid = np.meshgrid(np.linspace(np.min(X[:,0]),np.max(X[:,0]),100),
                          np.linspace(np.min(X[:,1]),np.max(X[:,1]),100))
gridinputs = np.vstack((xgrid.flatten(),ygrid.flatten())).T

A simple net

In [ ]:
model = keras.models.Sequential()
model.add(keras.layers.Dense(1,input_shape = (2,)))
model.compile(optimizer=keras.optimizers.Adam(lr=0.02),
                        loss="binary_crossentropy")

yhats = []
for i in tqdm.tqdm(list(range(10))):
    yhat = model.predict(gridinputs)
    yhat = np.reshape(yhat,xgrid.shape)
    yhats.append(yhat)
    model.fit(X,y,verbose = 0,epochs=10)
In [ ]:
extent = (np.min(X[:,0]),np.max(X[:,0]), np.min(X[:,1]), np.max(X[:,1]))

@widgets.interact(i=widgets.IntSlider(min=0,max=len(yhats)-1,step=1,value=0))
def f(i):
    fig,ax = plt.subplots(figsize=(18,9))         
    him = ax.imshow(yhats[i], vmin = 0, vmax = 1, cmap = "coolwarm",
              extent = extent,
              alpha = 0.5, origin = "lower")
    ax.contour(yhats[i], [0.5], extent = extent)
    ax.scatter(X[:,0],X[:,1],c = y.astype(float), cmap="coolwarm")
    ax.axis("off")
    ax.autoscale(enable=True, axis='both', tight=True)
    plt.colorbar(him)

Let's try a larger net

In [ ]:
model = keras.models.Sequential()
model.add(keras.layers.Dense(100,input_shape = (2,)))
model.add(keras.layers.Activation("sigmoid"))
model.add(keras.layers.Dense(100))
model.add(keras.layers.Activation("sigmoid"))
model.add(keras.layers.Dense(1))
model.add(keras.layers.Activation("sigmoid"))
model.compile(optimizer=
                    keras.optimizers.Adam(lr=0.01),
                    loss="binary_crossentropy")

yhats = []
for i in tqdm.tqdm(list(range(80))):
    yhat = model.predict(gridinputs)
    yhat = np.reshape(yhat,xgrid.shape)
    yhats.append(yhat)
    model.fit(X,y,verbose = 0,epochs=40)
In [ ]:
extent = (np.min(X[:,0]),np.max(X[:,0]), np.min(X[:,1]), np.max(X[:,1]))

@widgets.interact(i=widgets.IntSlider(min=0,max=len(yhats)-1,step=1,value=0))
def f(i):
    fig,ax = plt.subplots(figsize=(18,9))         
    him = ax.imshow(yhats[i], vmin = 0, vmax = 1, cmap = "coolwarm",
              extent = extent,
              alpha = 0.5, origin = "lower")
    ax.contour(yhats[i], [0.5], extent = extent)
    ax.scatter(X[:,0],X[:,1],c = y.astype(float), cmap="coolwarm")
    ax.axis("off")
    ax.autoscale(enable=True, axis='both', tight=True)
    plt.colorbar(him)
    

Part 2: let's create a basic convnet

In [ ]:
model = keras.models.Sequential()
model.add(keras.layers.Conv2D(1,(2,2),input_shape = (3,3,1)))
model.add(keras.layers.MaxPool2D((2,2)))
model.compile(optimizer=
              keras.optimizers.sgd(),
              loss="binary_crossentropy")

model.summary()
In [ ]:
img = np.array([
    [1,0,0],
    [0,2,0],
    [0,0,3]
])
weights = np.array([
    [0,1],
    [2,3]
])
model.layers[0].set_weights([
    weights[:,:,np.newaxis,np.newaxis],
    np.array([0.5])
])
model.predict(img[np.newaxis,:,:,np.newaxis])[0,:,:,0]
In [ ]:
grads = keras.backend.gradients(model.output, model.weights)
f = keras.backend.function([model.input], [grads[0]])
f([img[np.newaxis,:,:,np.newaxis]])[0][:,:,0,0]

A more complex quiz

In [ ]:
model = keras.models.Sequential()
model.add(keras.layers.Conv2D(2,(2,2),input_shape = (3,3,3)))
#model.add(keras.layers.MaxPool2D((2,2)))
model.compile(optimizer=
              keras.optimizers.sgd(),
              loss="binary_crossentropy")

model.count_params()

img0 = np.array([[0, 1, 0],
                 [0, 0, 0],
                 [0, 0, 0]])

img1 = np.array([[0, 0, 0],
                 [0, 0, 0],
                 [0, 0, 0]])

img2 = np.array([[0, 0, 0],
                 [0, 0, 0],
                 [0, 0,-2]])

img = np.stack((img0,img1,img2),axis=2)


weights00 = np.array([[0,1],
                      [2,3]])
weights01 = np.array([[0,0],
                      [0,1]])

weights10 = np.array([[0,0],
                      [0,0]])
weights11 = np.array([[0,0],
                      [0,0]])

weights20 = np.array([[0,1],
                      [2,3]])
weights21 = np.array([[5,4],
                      [8,7]])

weights = np.stack(
    (np.stack((weights00,weights10,weights20), axis=2),
     np.stack((weights01,weights11,weights21), axis=2)),
    axis = 3)

model.layers[0].set_weights([
    weights,
    np.array([0,0])
])
out = model.predict(img[np.newaxis,:,:,:])[0,:,:,:]
print(out[:,:,0])
print(out[:,:,1])